package com.superhelper.processor.order.consumer;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import com.aliyun.openservices.ons.api.Action;
import com.aliyun.openservices.ons.api.ConsumeContext;
import com.aliyun.openservices.ons.api.Consumer;
import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.MessageListener;
import com.aliyun.openservices.ons.api.ONSFactory;
import com.aliyun.openservices.ons.api.PropertyKeyConst;
import com.superhelper.common.Consts;
import com.superhelper.common.domain.AuserShop;
import com.superhelper.common.domain.POIStatus;
import com.superhelper.common.domain.POIStatusOperator;
import com.superhelper.common.domain.PushMsgType;
import com.superhelper.common.domain.TakeOutOrder;
import com.superhelper.common.domain.TakeOutOrderBackup;
import com.superhelper.common.domain.TakeOutOrderGroup;
import com.superhelper.common.domain.TakeOutOrderGroupItem;
import com.superhelper.common.domain.TakeOutOrderGroupType;
import com.superhelper.common.domain.TakeOutOrderStatus;
import com.superhelper.common.domain.TakeOutOrderType;
import com.superhelper.common.domain.User;
import com.superhelper.common.domain.mt.MtOrderPushEntity;
import com.superhelper.common.utils.GeoUtil;
import com.superhelper.common.utils.JsonHelper;
import com.superhelper.common.utils.JsonObjectUtil;

@Component
public class MtOrderConsumer extends AbstractOrderConsumer implements ApplicationListener<ContextRefreshedEvent> {
    private static final Logger log = LoggerFactory.getLogger(MtOrderConsumer.class);

    private Consumer consumer;
    @Value("${aliyun.access.key}")
    private String aliyunAccessKey;
    @Value("${aliyun.access.secret}")
    private String aliyunSecretKey;

    @Value("${aliyun.mt.order.consumer.id}")
    private String consumerId;
    @Value("${order.topic}")
    private String orderTopic;
    @Value("${online}")
    private boolean online;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (event.getApplicationContext().getParent() != null) {
            return;
        }
        if (consumer != null) {
            return;
        }
        init();
        String tag = orderTopic + online + "-mt";
        consumer.subscribe(orderTopic, tag, new MessageListener() {
            public Action consume(Message message, ConsumeContext context) {
                try {
                    String content = new String(message.getBody(), Consts.UTF8_CHARSET);
                    log.info("content is:{}", content);
                    MtOrderPushEntity entity = JsonHelper.fromJson(content, MtOrderPushEntity.class);
                    if (entity == null) {
                        log.error("MtOrderConsumer entity is null");
                        return Action.CommitMessage;
                    }
                    PushMsgType type = PushMsgType.getByMtType(entity.getPushType());
                    message.setTag(type.getValue());
                    if (StringUtils.equalsIgnoreCase(PushMsgType.ORDER_CREATED.getValue(), message.getTag())) {
                        createOrder(entity, content);
                    } else if (StringUtils.equalsIgnoreCase(PushMsgType.ORDER_ACCEPTED.getValue(), message.getTag())) {
                        dealOrder(TakeOutOrderStatus.VALID.getValue(), entity.getOrder(), type,
                                TakeOutOrderType.MeiTuan.getValue());
                    } else if (StringUtils.equalsIgnoreCase(PushMsgType.ORDER_CANCELED.getValue(), message.getTag())
                            || StringUtils.equalsIgnoreCase(PushMsgType.ORDER_AGREE_CANCEL.getValue(), message.getTag())) {
                        dealOrder(TakeOutOrderStatus.INVALID.getValue(), entity.getOrderCancel(), type,
                                TakeOutOrderType.MeiTuan.getValue());
                    } else if (StringUtils.equalsIgnoreCase(PushMsgType.ORDER_COMPLETED.getValue(), message.getTag())) {
                        dealOrder(TakeOutOrderStatus.SETTLED.getValue(), entity.getOrder(), type,
                                TakeOutOrderType.MeiTuan.getValue());
                    } else if (StringUtils.equalsIgnoreCase(PushMsgType.ORDER_REFUND.getValue(), message.getTag())) {
                        dealOrder(TakeOutOrderStatus.REFUNDING.getValue(), entity.getOrderRefund(), type,
                                TakeOutOrderType.MeiTuan.getValue());
                    } else if (StringUtils.equalsIgnoreCase(PushMsgType.ORDER_APPLY_CANCEL.getValue(), message.getTag())) {
                        dealOrder(TakeOutOrderStatus.APPLY_CANCEL.getValue(), entity.getOrderCancel(), type,
                                TakeOutOrderType.MeiTuan.getValue());
                    } else if (StringUtils.equalsIgnoreCase(PushMsgType.DELIVER_STATUS.getValue(), message.getTag())) {
                        dealDeliverStatus(entity);
                    } else if (StringUtils.equalsIgnoreCase(PushMsgType.POI_STATUS.getValue(), message.getTag())) {
                        dealPoiStatus(entity);
                    }

                } catch (Exception e) {
                    log.error("MtOrderConsumer error", e);
                    return Action.ReconsumeLater;
                }
                return Action.CommitMessage;
            }

        });
        consumer.start();
        log.info("consumer started");

    }

    private void dealPoiStatus(MtOrderPushEntity entity) {
        String poiStatus = entity.getPoiStatus();
        if (StringUtils.isBlank(poiStatus)) {
            return;
        }
        @SuppressWarnings("unchecked")
        Map<String, Object> map = JsonHelper.fromJson(poiStatus, Map.class);
        String shopId = MapUtils.getString(map, "ePoiId");
        // 121-营业；120-休息；18-上线；19-下线
        int status = MapUtils.getInteger(map, "poiStatus");
        // BUSINESS或者MEITUAN
        String operateUser = MapUtils.getString(map, "operateUser");
        String reason = MapUtils.getString(map, "reason");

        publishShopStatus(shopId, TakeOutOrderType.MeiTuan, POIStatus.mt(status), POIStatusOperator.mt(operateUser),
                reason);
    }

    private void dealDeliverStatus(MtOrderPushEntity entity) {
        String deliverStatus = entity.getShippingStatus();
        if (StringUtils.isBlank(deliverStatus)) {
            return;
        }
        @SuppressWarnings("unchecked")
        Map<String, Object> map = JsonHelper.fromJson(deliverStatus, Map.class);
        // long plfOrderId = MapUtils.getLong(map, "orderId");
        // 0-配送单发往配送;10-配送单已确认;20-骑手已取餐;40-骑手已送达;100-配送单已取消
        int status = MapUtils.getInteger(map, "shippingStatus");
        //
        // TakeOutOrder order = orderMapper.getByPlfOrderIdAndType(plfOrderId +
        // "", TakeOutOrderType.MeiTuan.getValue());
        // if (order == null) {
        // log.warn("can't find takeout_order;type:mt; plfOrderId:{}",
        // plfOrderId);
        // return;
        // }
        if (status == 40) {
            // if (!StringUtils.equalsIgnoreCase(order.getStatus(),
            // TakeOutOrderStatus.SETTLED.getValue())) {
            // orderMapper.updateSettledById(order.getId());
            // } else {
            // log.warn("ingore,beacause it's settled; takeout_order; type:mt;
            // orderId:{}", order.getId());
            // }
            // return;
            dealOrder(TakeOutOrderStatus.SETTLED.getValue(), entity.getShippingStatus(), PushMsgType.ORDER_COMPLETED,
                    TakeOutOrderType.MeiTuan.getValue());

        } else if (status <= 20) {
            // 暂时统一为配送中
            // if (!StringUtils.equalsIgnoreCase(order.getStatus(),
            // TakeOutOrderStatus.SETTLED.getValue())
            // && !StringUtils.equalsIgnoreCase(order.getStatus(),
            // TakeOutOrderStatus.DELIVERING.getValue())) {
            // orderMapper.updateDeliveringById(order.getId());
            // } else {
            // log.warn("ingore,beacause it's settled; takeout_order; type:mt;
            // orderId:{}", order.getId());
            // }

            dealOrder(TakeOutOrderStatus.DELIVERING.getValue(), entity.getShippingStatus(), PushMsgType.DELIVER_STATUS,
                    TakeOutOrderType.MeiTuan.getValue());
            return;
        }
        // 100的状态暂时不理，应该会再来一个订单取消的推送

        // TODO 这里要下发消息推送？
    }

    private void createOrder(MtOrderPushEntity entity, String content) {
        TakeOutOrder order = new TakeOutOrder();
        String msg = entity.getOrder();
        @SuppressWarnings({ "unchecked" })
        Map<String, Object> msgObj = JsonHelper.fromJson(msg, Map.class);
        order.setShopId(entity.getePoiId());
        convert(order, msgObj);
        String phone = CollectionUtils.isEmpty(order.getPhoneList()) ? order.getPhone() : order.getPhoneList().get(0);
        User user = null;
        if (StringUtils.isNotBlank(phone)) {
            AuserShop shop = orderMapper.getShop(order.getShopId(), order.getType());
            user = userMapper.getUser(phone, shop.getAuserId());
            if (user == null) {
                user = new User();
                user.setSource(TakeOutOrderType.MeiTuan.getValue());
                user.setPhone(phone);
                user.setCreateAt(new Date());
                user.setName(order.getConsigness());
                user.setMt_money(BigDecimal.valueOf(order.getTotalPrice()));
                user.setIntegral(BigDecimal.valueOf(order.getTotalPrice()).intValue());
                user.setEle_money(BigDecimal.ZERO);
                user.setAuserId(shop.getAuserId());
                userMapper.insertUser(user);
            }
        }
        order.setUserId(user != null ? user.getId() : 0l);

        TakeOutOrder too = orderMapper.getByPlfOrderIdAndType(order.getPlfOrderId(), order.getType());
        if (too != null) {
            log.info("MtOrderConsumer entity,plfOrderId:{} is duplicate msg", order.getPlfOrderId());
        } else {

            orderMapper.insertOrder(order);
            List<TakeOutOrderGroup> groups = order.getGroups();
            if (groups != null) {
                for (TakeOutOrderGroup group : groups) {
                    group.setOrderId(order.getId());
                    orderMapper.insertGroup(group);
                    List<TakeOutOrderGroupItem> items = group.getItems();
                    if (items != null) {
                        for (TakeOutOrderGroupItem item : items) {
                            item.setGroupId(group.getId());
                            item.setOrderId(group.getOrderId());
                            orderMapper.insertGroupItem(item);
                        }
                    }
                }
            }

            TakeOutOrderBackup orderBackup = new TakeOutOrderBackup();
            orderBackup.setOrderId(order.getId());
            orderBackup.setContent(content);
            orderMapper.insertOrderBackup(orderBackup);
            publish(order, PushMsgType.ORDER_CREATED, false);

        }
    }

    @SuppressWarnings("unchecked")
    private void convert(TakeOutOrder order, Map<String, Object> msgObj) {
        order.setType(TakeOutOrderType.MeiTuan.getValue());
        order.setPlfOrderId(JsonObjectUtil.getLong(msgObj.get("orderId")) + "");
        order.setPlfOrderCode(JsonObjectUtil.getLong(msgObj.get("orderIdView")) + "");
        order.setPlfCreateAt(getDate(JsonObjectUtil.getLong(msgObj.get("ctime"))));
        // 支付类型，参考的是美团的
        order.setPayType(getInt(msgObj.get("payType")));
        order.setActiveAt(order.getPlfCreateAt());
        order.setCreateAt(new Date());
        order.setDeliverFee(getDouble(msgObj.get("shippingFee")));
        order.setThirdDeliver(getInt(msgObj.get("isThirdShipping")) == 1);
        // 0000 商家自配送
        if ("0000".equals((String) (msgObj.get("logisticsCode")))) {
            order.setThirdDeliver(true);
        }
        Long deliverTime = JsonObjectUtil.getLong(msgObj.get("deliveryTime"));
        if (deliverTime == 0) {
            order.setDeliverTime(null);
            order.setBook(false);
        } else {
            order.setDeliverTime(getDate(deliverTime));
            order.setBook(true);
        }
        order.setDescription((String) msgObj.get("caution"));
        order.setInvoice((String) msgObj.get("invoiceTitle"));
        order.setInvoiced(JsonObjectUtil.getInt(msgObj.get("hasInvoiced")) == 1);

        order.setPhone((String) msgObj.get("recipientPhone"));
        order.setShopId((String) msgObj.get("ePoiId"));
        order.setShopName((String) msgObj.get("poiName"));
        order.setDaySn(NumberUtils.toInt((String) (msgObj.get("daySeq"))));
        order.setStatus(TakeOutOrderStatus.getByMtStatus(JsonObjectUtil.getInt(msgObj.get("status"))).getValue());
        order.setRefundStatus("noRefund");
        order.setPlfUserId(0l);
        order.setTotalPrice(getDouble(msgObj.get("total")));
        order.setOriPrice(getDouble(msgObj.get("originalPrice")));
        order.setHongbao(0d);
        order.setServiceRate(0d);
        order.setActivityTotal(0d);
        String poiReceiveDetail = (String) msgObj.get("poiReceiveDetail");
        if (StringUtils.isNotBlank(poiReceiveDetail)) {
            Map<String, Object> poiDetailMap = (Map<String, Object>) JsonHelper.fromJson(poiReceiveDetail, Map.class);

            order.setIncome(getInt(poiDetailMap.get("wmPoiReceiveCent")) / 100d);
            order.setServiceFee(getInt(poiDetailMap.get("foodShareFeeChargeByPoi")) / 100d);

            List<Map<String, Object>> mtCharge = (List<Map<String, Object>>) poiDetailMap.get("actOrderChargeByMt");
            double plfPart = 0d;
            if (!CollectionUtils.isEmpty(mtCharge)) {
                for (Map<String, Object> m : mtCharge) {
                    plfPart += getInt(m.get("moneyCent")) / 100d;
                }
            }
            order.setPlfPart(plfPart);
            double shopPart = 0d;
            List<Map<String, Object>> poiCharge = (List<Map<String, Object>>) poiDetailMap.get("actOrderChargeByPoi");
            if (!CollectionUtils.isEmpty(poiCharge)) {
                for (Map<String, Object> m : poiCharge) {
                    shopPart += getInt(m.get("moneyCent")) / 100d;
                }
            }
            order.setShopPart(shopPart);
        }
        order.setConsigness((String) msgObj.get("recipientName"));

        order.setDeliverLon(JsonObjectUtil.getDouble(msgObj.get("longitude")));
        order.setDeliverLat(JsonObjectUtil.getDouble(msgObj.get("latitude")));

        AuserShop s = orderMapper.getShop(order.getShopId(), order.getType());

        if (s != null) {
            order.setAuserId(s.getAuserId().longValue());
            order.setDist(GeoUtil.calDist(order.getDeliverLon(), order.getDeliverLat(), s.getLon(), s.getLat()));
        }
        String address = (String) msgObj.get("recipientAddress");
        order.setDeliverPoi(address.replaceAll("@#.*$", ""));

        // order.setServiceFee(getDouble(msgObj.get("serviceFee")));
        // order.setServiceRate(getDouble(msgObj.get("serviceRate")));
        // order.setHongbao(getDouble(msgObj.get("hongbao")));

        // order.setActivityTotal(getDouble(msgObj.get("activityTotal")));
        // order.setShopPart(getDouble(msgObj.get("shopPart")));
        // order.setPlfPart(getDouble(msgObj.get("elemePart")));
        // build Groups

        List<TakeOutOrderGroup> groups = new ArrayList<>();
        List<TakeOutOrderGroup> extraGroups = new ArrayList<>();

        Double packageFee = 0d;
        // 商品明细
        String detailStr = (String) msgObj.get("detail");
        if (StringUtils.isNotBlank(detailStr)) {
            List<Map<String, Object>> detailList = (List<Map<String, Object>>) JsonHelper.fromJson(detailStr,
                    List.class);
            if (!CollectionUtils.isEmpty(detailList)) {

                for (Map<String, Object> itemMap : detailList) {
                    TakeOutOrderGroup group = null;
                    int cartId = getInt(itemMap.get("cart_id"));
                    if (cartId < 0) {
                        log.info("orderId:{}, cart_id = -1 ", order.getPlfOrderId());
                        cartId = 0;
                    }
                    if (groups.size() < cartId + 1) {
                        group = new TakeOutOrderGroup();
                        group.setName(cartId + 1 + "号口袋");
                        group.setType(TakeOutOrderGroupType.Normal.getValue());
                        groups.add(group);
                        List<TakeOutOrderGroupItem> items = new ArrayList<>();
                        group.setItems(items);
                    } else {
                        group = groups.get(cartId);
                    }

                    TakeOutOrderGroupItem item = new TakeOutOrderGroupItem();
                    group.getItems().add(item);
                    item.setQuantity(getInt(itemMap.get("quantity")));
                    item.setPrice(0.0d + getDouble(itemMap.get("price")));
                    item.setTotal(item.getQuantity() * item.getPrice());

                    item.setBarCode(null);
                    item.setExtendCode(null);
                    item.setSkuId((String) (itemMap.get("sku_id")));
                    item.setName((String) itemMap.get("food_name"));
                    item.setCategoryId(getInt(itemMap.get("categoryId")) + "");

                    item.setAttributes((String) (itemMap.get("food_property")));
                    item.setNewSpecs((String) (itemMap.get("spec")));
                    item.setWeight(1d);
                    int boxNum = getInt(itemMap.get("box_num"));
                    double boxPrice = getDouble(itemMap.get("box_price"));
                    if (boxNum > 0) {
                        double boxTotal = boxNum * boxPrice;
                        TakeOutOrderGroup g = new TakeOutOrderGroup();
                        g.setType(TakeOutOrderGroupType.Extra.getValue());
                        g.setName("其他费用");
                        g.setItems(new ArrayList<TakeOutOrderGroupItem>());
                        extraGroups.add(g);
                        TakeOutOrderGroupItem gi = new TakeOutOrderGroupItem();
                        gi.setPrice(boxPrice);
                        gi.setQuantity(boxNum);
                        gi.setTotal(boxTotal);
                        gi.setName("餐盒");
                        gi.setSkuId("-1");
                        gi.setWeight(0d);
                        g.getItems().add(gi);
                        packageFee += boxTotal;
                    }
                    Map<String, Object> additions = new HashMap<>();
                    additions.put("foodDiscount", getDouble(itemMap.get("food_discount")));
                    additions.put("appFoodCode", (String) itemMap.get("app_food_code"));
                    additions.put("unit", (String) itemMap.get("unit"));
                    item.setAdditions(JsonHelper.toJson(additions));
                }
            }
        }
        groups.addAll(extraGroups);
        order.setGroups(groups);
        order.setPackageFee(packageFee);
        // 费用明细
        // List<Map<String, Object>> extrasList = (List<Map<String, Object>>)
        // msgObj.get("extras");
        // if (!CollectionUtils.isEmpty(extrasList)) {
        // TakeOutOrderGroup group = new TakeOutOrderGroup();
        // group.setName(TakeOutOrderGroupType.Discount.getDesc());
        // group.setType(TakeOutOrderGroupType.Discount.getValue());
        // groups.add(group);
        // List<TakeOutOrderGroupItem> items = new ArrayList<>();
        // group.setItems(items);
        // for (Map<String, Object> itemMap : detailList) {
        //
        // TakeOutOrderGroupItem item = new TakeOutOrderGroupItem();
        // items.add(item);
        // item.setQuantity(getInt(itemMap.get("quantity")));
        // item.setPrice(getDouble(itemMap.get("price")));
        // item.setTotal(item.getQuantity() * item.getPrice());
        //
        // item.setBarCode(null);
        // item.setExtendCode(null);
        // item.setSkuId((String) (itemMap.get("act_detail_id")));
        // item.setName((String) itemMap.get("food_name"));
        // item.setCategoryId(getInt(itemMap.get("categoryId")) + "");
        //
        // item.setAttributes((String) (itemMap.get("food_property")));
        // item.setNewSpecs((String) (itemMap.get("spec")));
        // item.setWeight(0d);
        // packageFee += getInt(itemMap.get("box_num")) *
        // getDouble(itemMap.get("box_price"));
        //
        // Map<String, Object> additions = new HashMap<>();
        // additions.put("foodDiscount",
        // getDouble(itemMap.get("food_discount")));
        // additions.put("appFoodCode", (String) itemMap.get("app_food_code"));
        // additions.put("unit", (String) itemMap.get("unit"));
        // item.setAdditions(JsonHelper.toJson(additions));
        // }
        // }
    }

    private static Integer getInt(Object obj) {
        if (obj == null) {
            return 0;
        }
        if (obj instanceof Long) {
            return ((Long) obj).intValue();
        }
        if (obj instanceof Double) {
            return ((Double) obj).intValue();
        }
        return (Integer) obj;
    }

    private static Double getDouble(Object obj) {
        if (obj == null) {
            return 0D;
        }
        if (obj instanceof Double) {
            return (Double) obj;
        } else if (obj instanceof Integer) {
            return BigDecimal.valueOf((Integer) obj).doubleValue();
        }
        return 0d;
    }

    public static void main(String[] args) {
        String msg = null;
        try {
            msg = FileUtils.readFileToString(new File("D:/detail.txt"), "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        TakeOutOrder order = new TakeOutOrder();
        @SuppressWarnings({ "unchecked" })
        Map<String, Object> msgObj = JsonHelper.fromJson(msg, Map.class);
        new MtOrderConsumer().convert(order, msgObj);
        System.out.println(JsonHelper.toJson(order));
        //
        // String str = "富景花苑 (广和路42号5楼502C房)@#广东省广州市天河区广和路广和路72号富景花苑";
        // System.out.println(str.replaceFirst("@#.*$", ""));
        // Properties properties = new Properties();
        // properties.put(PropertyKeyConst.ConsumerId, "CID_super_test");
        // properties.put(PropertyKeyConst.AccessKey, "LTAIayggS1c9jA2q");
        // properties.put(PropertyKeyConst.SecretKey,
        // "u7XDsuMBjLvkzdn3o6Sct7PhEQQ5Kw");
        // Consumer consumer1 = ONSFactory.createConsumer(properties);
        //
        // consumer1.subscribe("super_test", "aaa", new MessageListener() {
        //
        // @Override
        // public Action consume(Message message, ConsumeContext context) {
        // System.out.println(new String(message.getBody()));
        // try {
        // Thread.sleep(1000);
        // } catch (InterruptedException e) {
        // }
        // return Action.CommitMessage;
        // }
        // });
        // consumer1.start();
    }

    private static Date getDate(Long unixTime) {
        if (unixTime == null || unixTime <= 0) {
            return new Date();
        }
        return new Date(unixTime * 1000);
    }

    private void init() {
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.ConsumerId, consumerId);
        properties.put(PropertyKeyConst.AccessKey, aliyunAccessKey);
        properties.put(PropertyKeyConst.SecretKey, aliyunSecretKey);
        consumer = ONSFactory.createConsumer(properties);
    }

}
